/**
 * Framework for batch testing user profile models
 * Final project by Sergey Nepomnyachiy and Julia Polchin
 * Supervisor: Tsvi Kuflik
 *
 */

package core;

import interfaces.ComponentInterface;
import interfaces.LoggingInterface;
import interfaces.GeneratorInterface;
import interfaces.ProgressKeeperInterface;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Vector;

import backend.DummyProgKeeper;
import backend.FileSystem;
import backend.Stats;
import core.environment.Defines;

/**
 * @author Sergey and Julia
 * 
 */
public class Users implements ComponentInterface {
	private LoggingInterface fs;
	private Vector<Step> steps;
	private GeneratorInterface<?> gen;
	private Constructor<?> ctor;
	private ProgressKeeperInterface pk;
	
	/**
	 * Construct a user
	 * @param fs Logging backend
	 * @param ctor Constructor of user profile
	 * @param gen Generator for constructors arguments
	 */
	public Users(LoggingInterface fs, Constructor<?> ctor,
			GeneratorInterface<?> gen) {
		this.fs = fs;
		this.steps = new Vector<Step>();
		this.gen = gen;
		this.ctor = ctor;
		this.pk = new DummyProgKeeper();
	}

	@SuppressWarnings({ "unchecked", "boxing" })
	@Override
	public boolean execute() {
		Integer userCounter = 0;
		Collection<?> usersData = this.gen.getVector();
		
		this.pk.add(usersData.size());
		
		for (Object obj : usersData) {

			Object[] args;
			if (this.gen.is2D() == false) {
				Object[] a = { obj };
				args = a;
			} else
				args = ((Vector<Object>) obj).toArray();

			Object newInstance = null;
			try {
				newInstance = this.ctor.newInstance(args);
			} catch (IllegalArgumentException e) {
				Defines.printException(e.getMessage());
			} catch (InstantiationException e) {
				Defines.printException(e.getMessage());
			} catch (IllegalAccessException e) {
				Defines.printException(e.getMessage());
			} catch (InvocationTargetException e) {
				Defines.printException(e.getMessage());
			}

			userCounter++;

			LoggingInterface efs = new FileSystem(this.fs,(userCounter).toString()+".u");
			for (Step s : this.steps) {

				s.setFs(efs);
				s.setInstance(newInstance);
				s.execute(userCounter);
			}

			Collection<Object> observed = UserObservedPredictedHolder.getInstance().getObserved();
			Collection<Object> predicted = UserObservedPredictedHolder.getInstance().getPredicted();

			efs.write(null,"predicted="+predicted+"\n");
			efs.write(null,"observed="+observed+"\n");
			efs.write(null,"correlation="+Stats.getCorrelation(observed, predicted)+"\n");
			efs.write(null,"mae="+Stats.getMAE(observed, predicted)+"\n");
			
			GroupObservedPredictedHolder.getInstance().addPredictedObserved(observed, predicted);
			UserObservedPredictedHolder.getInstance().clearObserved();
			UserObservedPredictedHolder.getInstance().clearPredicted();
			this.pk.increment();
			

		}

		return true;
	}

	@Override
	public void setFs(LoggingInterface fs) {
		this.fs = fs;

	}

	/**
	 * Adding new step to users
	 * @param stp new step to add
	 */
	public void addStep(Step stp) {
		this.steps.add(stp);
	}

	@Override
	public void setProgresser(ProgressKeeperInterface pk) {
		this.pk = pk;
		
	}
}